<template>
  <el-upload
    ref="uploadRef"
    class="upload-demo"
    :http-request="handleUploadFile"
    :multiple="isMultiple"
    :on-preview="handlePreview"
    :on-remove="handleRemove"
    :before-remove="beforeRemove"
    :limit="limit"
    :auto-upload="isUpload"
    :on-exceed="handleExceed"
  >
    <template #trigger>
      <el-button slot="trigger" type="primary">选择文件</el-button>
    </template>
    <template #tip>
      <div class="el-upload__tip">文件上传</div>
    </template>
  </el-upload>
  <el-button type="success" @click="handleRequest">上传</el-button>
</template>

<script setup>
import SparkMD5 from "spark-md5";
const limit = 1;
const fileList = ref([]); //上传的文件列表
const isUpload = ref(false); //是否自动上传
const isMultiple = ref(false); //是否支持多选文件上传
const uploadRef = ref(null);
let chunkSize = 1024 * 1024 * 1; //分片大小
let chunks = []; //分片数组
let uploadedChunks = 0; //已上传的分片数
let currentFile = null; //当前上传的文件
let fileHash = ""; // 文件的哈希值
let chunkHash = ref([]);

/**
 * 点击文件列表中已上传的文件时的钩子
 */
const handlePreview = (uploadFile) => {
  console.log("点击文件列表中已上传的文件时的钩子", uploadFile);
};
/**
 * 文件列表移除文件时的钩子
 */
const handleRemove = () => {};
/**
 * 删除文件之前的钩子，参数为上传的文件和文件列表
 * 若返回 false 或者返回 Promise 且被 reject，则停止删除。
 */
const beforeRemove = () => {};
/**
 * 当超出限制时，执行的钩子函数
 */
const handleExceed = () => {
  ElMessage({
    message: "超出文件上传的限制",
    type: "warning",
  });
};

/**
 * 上传功能
 */
const handleRequest = () => {
  uploadRef.value.submit();
};
/**
 * 上传文件
 * @param e
 * @returns {Promise<void>}
 */
const handleUploadFile = async (e) => {
  currentFile = e.file;
  await calculateFileHash(e.file);
  await calculateChunks(e.file);
  await uploadChunks();
};
/**
 * 计算整个文件哈希值
 * @param file
 * @returns {Promise<unknown>}
 */
const calculateFileHash = (file) => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = (e) => {
      const spark = new SparkMD5.ArrayBuffer();
      spark.append(e.target.result);
      resolve(spark.end());
    };
    reader.onerror = (e) => {
      reject(e);
    };
    reader.readAsArrayBuffer(file);
  });
};
/**
 * 计算每个分片的哈希值
 * @param chunk
 * @returns {Promise<void>}
 */
const calculateChunkHash = (chunk) => {
  return new Promise((resolve, reject) => {
    const chunkReader = new FileReader();
    chunkReader.onload = (e) => {
      const spark = new SparkMD5.ArrayBuffer();
      spark.append(e.target.result);
      resolve(spark.end());
    };
    chunkReader.onerror = (e) => {
      reject(e);
    };
    chunkReader.readAsArrayBuffer(chunk);
  });
};

/**
 * 计算分片
 * @param file
 * @returns {Promise<*[]>}
 */
const calculateChunks = async (file) => {
  const chunkCount = Math.ceil(file.size / chunkSize);
  console.log("chunkCount", chunkCount);
  let startPos = 0;
  while (startPos < file.size) {
    const chunk = file.slice(startPos, startPos + chunkSize);
    const hash = await calculateChunkHash(chunk);
    chunkHash.value.push(hash);
    chunks.push(chunk);
    startPos += chunkSize;
  }
  console.log("chunks", chunks);
  console.log("chunkHash", chunkHash.value);
  return chunks;
};
/**
 * 上传分片
 */
const uploadChunks = () => {
  for (let i = 0; i < chunks.length; i++) {
    const hash = chunkHash.value[i];
    console.log("hash", hash);
    const formData = new FormData();
    formData.append("file", chunks[i]);
    formData.append("chunkIndex", i);
    formData.append("chunkTotal", chunks.length);
    formData.append("fileName", currentFile.name);
    formData.append("fileHash", hash);
  }
};
</script>

<style lang="scss" scoped></style>
